import 'dart:developer';

import 'package:terms/terms.dart';

export 'package:terms/data/chess_terms.dart';
export 'package:terms/common.dart';
export 'package:terms/util/tool.dart';
export 'package:terms/util/print.dart';
export 'package:terms/terms_direction.dart';
export 'package:terms/terms_line.dart';
export 'package:terms/special_dot.dart';
export 'package:terms/basic_terms.dart';
export 'package:terms/common_terms.dart';
export 'package:terms/composite_terms.dart';
export 'package:terms/direction_terms.dart';
export 'package:terms/parataxis_terms.dart';
export 'package:terms/special_terms.dart';
export 'package:terms/combine_terms.dart';
export 'package:terms/data/terms_coordinates.dart';
export 'package:tile/tile.dart';
export 'package:terms/data/tile_ext.dart';
export 'package:terms/terms.dart';
export 'package:terms/direction.dart';

/// 记录历史术语
List<ChessTerms> chessTerms = List.empty(growable: true);

/// 复合术语是否已经判定过
bool isHaveJudgeComposite = false;

enum ColorMode { all, different, same }

/// 术语2.0
enum Terms {
  none(''),
  chess('棋'),
  pass('pass'),
  ko('劫'),
  capture('提子'),
  captureKo('提劫'),
  multiStrikePayback('打多还一'),
  sacrifice('扑'),
  sacrificeBackSacrifice('扑(倒扑)'),
  atari('打吃'),
  atariTurn('打吃(拐吃)'),
  doubleAtari('双打'),
  makeEye('做眼'),
  makeKo('做劫'),
  findKo('找劫'),
  crowd('挤'),
  crowdOneOne('挤(一一)'),
  crowdTwoTwo('挤(二二)'),
  crowdThreeThree('挤(三三)'),
  cut('断'),
  cutAtari('断(断打)'),
  crushCut('断(冲断)'),
  stick('粘'),
  connect('连接'),
  stickConnect('连接(粘)'),
  pullStick('粘(扳粘)'),
  group('团'),
  dig('挖'),
  digStick('粘(挖粘)'),
  crush('冲'),
  tiger('虎'),
  doubleTiger('双虎'),
  smallJump('小跳'),
  dot('点'),
  dotOneOne('点(一一)'),
  dotTwoTwo('点(二二)'),
  dotThreeThree('点(三三)'),
  sharp('尖'),
  pull('扳'),
  doublePull('扳(连扳)'),
  turn('拐'),
  resist('挡'),
  sharpTop('尖顶'),
  sharThrust('尖刺'),
  poke('碰'),
  shoulderHit('肩冲'),
  block('拦'),
  stretch('并'),
  stretchPillar('并(玉柱)'),
  smallFly('小飞'),
  elephantStep('象步'),
  jump('跳'),
  bigJump('大跳'),
  bigFly('大飞'),
  superBigJump('超大跳'),
  superBigFly('超大飞'),
  thrustPeep('刺(尖刺)'),
  thrustTigerThorn('刺(虎刺)'),
  peep('尖刺'),
  wedge('尖穿'),
  breakWedge('断(尖穿)'),
  thrust('刺'),
  jumpThrust('跳刺'),
  breakElephantEye('穿象眼'),
  diagonalConnect('尖连'),
  connectDiagonalConnect('连接(尖连)'),
  top('顶'),
  press('压'),
  climb('爬'),
  depend('靠'),
  hold('托'),
  holdTwoTwo('托(二二)'),
  holdThreeThree('托(三三)'),
  attach('贴'),
  breakOne('拆一'),
  oneOneEnter('一一塞入'),
  twoTwoHold('二二托'),
  threeThreeHold('三三托'),
  starDepend('星位靠'),
  breakTwo('拆⼆'),
  bigFlyEnclosure('大飞守角'),
  threeThreeInvasion('三三挂'),
  smallEyeHighInvasion('⼩⽬⾼挂'),
  smallEyeInvasionCorner('⼩⽬挂⻆'),
  starHighInvasion('星位⾼挂'),
  starInvasionCorner('星位挂⻆'),
  suppress('镇'),
  flySuppress('飞镇'),
  leak('漏'),
  leakTwoFourInvadeSplit('漏(二四侵分)'),
  leakTwoFiveInvadeSplit('漏(二五侵分)'),
  prevent('阻'),
  preventCross('阻渡'),
  disconnect('断开'),
  backTiger('倒虎'),
  tigerBackTiger('虎(倒虎)'),
  tigerThorn('虎刺'),
  clamp('夹'),
  flail('枷'),
  reducingMove('侵消'),
  starPoint('星位'),
  smallEye('小目'),
  outsideEye('目外'),
  highPoint('高目'),
  superOutsideEye('超目外'),
  superHighPoint('超高目'),
  tYuan('天元'),
  long('长'),
  stand('立'),
  back('退'),
  split('分投'),
  invasion('打入'),
  flyPress('飞压'),
  flyThrust('飞刺'),
  dotSquare('点方'),
  jumpSquare('跳方'),
  smallLedge('小伸腿'),
  bigLedge('大伸腿'),
  trimEdge('拆边'),
  trimEdgeTrimOne('拆边(拆一)'),
  trimEdgeFlyTrim('拆边(飞拆)'),
  trimEdgeTrimTwo('拆边(拆二)'),
  trimEdgeBigFlyTrim('拆边(大飞拆)'),
  doubleStrike('夹击'),
  doubleStrikeOneLowStrike('夹击(—间低夹)'),
  doubleStrikeOneHighStrike('夹击(—间高夹)'),
  trimEdgeLowTrimThree('拆边(低拆三)'),
  trimEdgeHighTrimThree('拆边(高拆三)'),
  worryFreeCorner('无忧角'),
  smallEyeEnclosure('小目守角'),
  smallEyeDgEnclosure('小目单关守角'),
  smallFlyEnclosure('小飞守角'),
  starEnclosure('星位守角'),
  starDgEnclosure('星位单关守角'),
  bigJumpEnclosure('大跳守角'),
  starBigJumpEnclosure('星位大跳守角'),
  starBreakTwoEnclosure('星位拆⼆守⻆'),
  doubleStrikeTwoLowStrike('夹击(二间低夹)'),
  doubleStrikeTwoHighStrike('夹击(二间高夹)'),
  doubleStrikeThreeLowStrike('夹击(三间低夹)'),
  doubleStrikeThreeHighStrike('夹击(三间高夹)'),
  kEnclosureSmallFlyEnclosure('缔角(小飞守角)'),
  kEnclosureDgEnclosure('缔角(单关守角)'),
  kEnclosureSmallJumpEnclosure('缔角(小跳守角)'),
  kEnclosureWorryFreeCorner('缔角(无忧角)'),
  kEnclosureBigFlyEnclosure('缔角(大飞守角)'),
  kEnclosureBigJumpEnclosure('缔角(大跳守角)'),
  cornerApproach('挂角'),
  cornerApproachSmallFlyApproachMove('挂角(小飞挂角)'),
  cornerApproachHighHangStar('挂角(高挂星位)'),
  cornerApproachSmallEyeEnclosure('挂角(小目挂角)'),
  cornerApproachSmallFlyEnclosure('挂角(小飞挂角)'),
  cornerApproachHighHang('挂角(高挂)'),
  cornerApproachBigFlyCornerApproach('挂角(大飞挂角)'),
  cornerApproachTwoHighHang('挂角(二间高挂)'),
  oneOne('一一'),
  twoTwo('二二'),
  threeThree('三三'),
  monkey('猴');

  final String desc;

  const Terms(this.desc);
}

String allTerms(String sgf) {
  var startTime = DateTime.now().millisecondsSinceEpoch;
  var tempBoard = Board(19);
  tempBoard.showSgfGame(sgf);
  var count = tempBoard.getCount();
  var originAllStep = tempBoard.allStep;
  log('originAllStep:$originAllStep');
  tempBoard.back(999);
  printInfo('count:$count');
  for (var i = 0; i < count; i++) {
    tempBoard.next(1);
    tempBoard.currNode.c = termsInfo(
      tempBoard,
      originAllStep: originAllStep,
      type: 1,
    );
  }
  var finalSgf = tempBoard.toSgf();
  log('finalSgf:$finalSgf');
  var endTime = DateTime.now().millisecondsSinceEpoch;
  log('time:${(endTime - startTime) / 1000.0}');
  return finalSgf;
}

/// 将术语赋值给board.currNode.c
String termsInfo(Board board, {String originAllStep = '', int type = 0}) {
  isHaveJudgeComposite = false;

  for (var it in chessTerms) {
    if (it.count == board.getCount()) {
      return it.terms;
    }
  }
  var terms = chessDescription(board, type: type, originAllStep: originAllStep);
  chessTerms.add(
    ChessTerms()
      ..count = board.getCount()
      ..terms = terms,
  );
  return terms;
}

/// 当前手的围棋术语：基础术语 > 常用术语 > 复合术语 > 并列术语 > 特殊术语 > 组合术语
String chessDescription(
  Board board, {
  String originAllStep = '',
  int type = 0,
}) {
  String finalTerms = '';
  // 空棋盘或最后1手直接返回棋
  if (board.getCount() == 0 || (type == 0 && board.isLast)) {
    return Terms.chess.desc;
  }
  String steps = board.allStep;
  ChessStep? nextStep = type == 0
      ? board.nextOrderedStep!
      : board.lastOrderedStep!;
  Board tempBoard = Board(board.getBoardSize());
  tempBoard.showYzSteps(steps);
  if (type == 0) {
    tempBoard.showXY(nextStep.x, nextStep.y); // 会影响打吃
  }

  var basicTerms = judgeBasicTerms(tempBoard, nextStep);
  printInfo('基础术语:$basicTerms');

  if (basicTermsList1.contains(basicTerms) || basicTerms.endsWith('子')) {
    return basicTerms;
  }

  // 找劫
  // if (type == 0) {
  if (backTerms(1, board) == Terms.ko.desc &&
      nextTerms(2, board, originAllStep, type: type) == Terms.ko.desc) {
    if (basicTerms.isNotEmpty) {
      basicTerms = '${Terms.findKo.desc}($basicTerms)';
      return basicTerms;
    } else {
      basicTerms = Terms.findKo.desc;
    }

    // printInfo('basicTerms:$basicTerms');
  }
  // }

  /// 组合术语最终判定
  /// 断（断打）>断（冲断）>打吃（拐吃）
  for (var value in basicTermsList2) {
    if (basicTerms.contains(value)) {
      return value;
    }
  }

  final commonTermsList = [
    Terms.pullStick.desc,
    Terms.digStick.desc,
    Terms.doublePull.desc,
    Terms.stickConnect.desc,
    Terms.climb.desc,
    Terms.press.desc,
  ];

  /// 粘（扳粘）>粘（挖粘）
  var tempTerms = descFromCoordinates(board, nextStep);
  for (var value in commonTermsList) {
    if (tempTerms.contains(value)) {
      return value;
    }
  }

  finalTerms = '$basicTerms,$tempTerms';
  finalTerms = finalTerms.replaceAll('棋', '');

  if (finalTerms.contains(Terms.block.desc) &&
      finalTerms.contains(Terms.flySuppress.desc)) {
    return Terms.flySuppress.desc;
  }

  printInfo('最终术语:$finalTerms');

  // 去重
  finalTerms = removeSame(finalTerms);

  /// 同时包含尖顶和小飞、则为尖顶
  if (finalTerms.contains(Terms.sharpTop.desc)) {
    if (finalTerms.contains(Terms.smallFly.desc)) {
      return Terms.sharpTop.desc;
    }
  }

  /// 同时包含并和飞镇
  if (finalTerms.contains(Terms.stretch.desc)) {
    if (finalTerms.contains(Terms.flySuppress.desc)) {
      return Terms.stretch.desc;
    }
  }

  if (finalTerms.contains(Terms.tiger.desc)) {
    if (finalTerms.contains(Terms.crowd.desc)) {
      return Terms.crowd.desc;
    }
    if (finalTerms.contains(Terms.resist.desc)) {
      return Terms.resist.desc;
    }
    if (finalTerms.contains(Terms.back.desc)) {
      return Terms.back.desc;
    }
    if (finalTerms.contains(Terms.long.desc)) {
      return Terms.long.desc;
    }
    if (finalTerms.contains(Terms.top.desc)) {
      return Terms.top.desc;
    }
  }

  var termArray = finalTerms.split(',');
  termArray.removeWhere((element) => element.isEmpty);
  finalTerms = '';
  if (termArray.isNotEmpty) {
    for (var it in termArray) {
      finalTerms += '$it,';
    }
    finalTerms = finalTerms.substring(0, finalTerms.length - 1);
  }

  // printInfo('finalTerms:$finalTerms');

  if (termArray.contains(Terms.tiger.desc)) {
    if (hasCommonElement(boxTerms1, finalTerms) >= 0) {
      termArray = finalTerms.split(',');
      for (var it in termArray) {
        if (boxTerms1.any((value) => it.contains(value))) {
          finalTerms = it;
        }
      }
    } else {
      return Terms.tiger.desc;
    }
  }

  /// 同时包含打吃和拐
  if (finalTerms.contains(Terms.atari.desc) &&
      finalTerms.contains(Terms.turn.desc)) {
    finalTerms = Terms.atariTurn.desc;
  }

  /// 碰与S6小跳 、S7小飞 、S8象步 、S9大跳 、S10大飞 、S3镇 、S13飞镇 、S14镇 、S15镇的任意—个即为“靠” 。
  if (finalTerms.contains(Terms.poke.desc) &&
      hasCommonElement(boxTerms2, finalTerms) >= 0) {
    finalTerms = Terms.depend.desc;
  }

  /// 肩冲&S6小跳:小跳  肩冲&S7小飞:飞压
  if (finalTerms.contains(Terms.shoulderHit.desc)) {
    if (finalTerms.contains(Terms.smallJump.desc)) {
      finalTerms = Terms.smallJump.desc;
    } else if (finalTerms.contains(Terms.smallFly.desc)) {
      finalTerms = Terms.flyPress.desc;
    } else if (finalTerms.contains(Terms.threeThree.desc)) {
      finalTerms = Terms.dotThreeThree.desc;
    }
  }

  if (finalTerms.contains(Terms.smallJump.desc)) {
    if (finalTerms.contains(Terms.thrust.desc)) {
      return Terms.jumpThrust.desc;
    } else if (finalTerms.contains(Terms.sharp.desc)) {
      return Terms.sharp.desc;
    } else if (finalTerms.contains(Terms.trimEdgeTrimOne.desc)) {
      return Terms.trimEdgeTrimOne.desc;
    } else if (finalTerms.contains(Terms.hold.desc)) {
      return Terms.hold.desc;
    } else {
      return Terms.smallJump.desc;
    }
  }

  /// 点与S6小跳 、S7小飞 、S10大飞的任意—个重叠改为所重叠的名称术语。
  if (finalTerms.contains(Terms.dot.desc)) {
    if (finalTerms.contains(Terms.smallJump.desc)) {
      finalTerms = Terms.smallJump.desc;
    } else if (finalTerms.contains(Terms.smallFly.desc)) {
      finalTerms = Terms.smallFly.desc;
    } else if (finalTerms.contains(Terms.bigFly.desc)) {
      finalTerms = Terms.bigFly.desc;
    }
  }

  if (finalTerms.contains(Terms.dotSquare.desc)) {
    return Terms.dotSquare.desc;
  } else if (finalTerms.contains(Terms.jumpSquare.desc)) {
    return Terms.jumpSquare.desc;
  }

  if (hasCommonElement([Terms.sharp.desc], finalTerms) >= 0) {
    if (finalTerms.contains(Terms.back.desc)) {
      return Terms.back.desc;
    }
    return Terms.sharp.desc;
  }

  /// 小伸腿、大伸腿
  if (finalTerms.contains(Terms.smallLedge.desc)) {
    return Terms.smallLedge.desc;
  } else if (finalTerms.contains(Terms.bigLedge.desc)) {
    return Terms.bigLedge.desc;
  }

  /// 同时包含刺和拆边，则是刺
  if (finalTerms.contains(Terms.thrust.desc) &&
      finalTerms.contains(Terms.trimEdge.desc)) {
    return Terms.thrust.desc;
  }

  if (finalTerms.contains(Terms.doubleTiger.desc)) {
    return Terms.doubleTiger.desc;
  }

  /// 小飞 、象步 、大跳 、大飞 、镇 、超大跳 、超大飞 、飞镇 、侵消这些术语,有拆边 、挂角 、拦 、夹击等优先选后—种情况。
  if (hasCommonElement(boxTerms3, finalTerms) >= 0) {
    var array = finalTerms.split(',');
    for (var it in array) {
      if (boxTerms5.any((value) => it.contains(value))) {
        finalTerms = it;
      } else {
        continue;
      }
    }
  }

  /// 挡
  var termsArray = finalTerms.split(',');
  if (termsArray.contains(Terms.resist.desc)) {
    return Terms.resist.desc;
  }

  /// 特殊术语处理：当出现拆边、拦术语后进行一次强判定
  if (finalTerms.contains(Terms.trimEdge.desc) ||
      finalTerms.contains(Terms.block.desc)) {
    var combineTerms = judgeCombineTerms(board, nextStep);
    if (combineTerms.isEmpty) {
      combineTerms = judgeCombineTerms(board, nextStep, isForce: true);
      printInfo('combineTerms:$combineTerms');
      if (combineTerms.isNotEmpty) {
        finalTerms = combineTerms;
      }
    }
  }

  if (finalTerms.contains(Terms.findKo.desc)) {
    var split = finalTerms.split(',');
    return '${Terms.findKo.desc}(${split[1]})';
  }

  // if (finalTerms.contains(Terms.oneOne.desc)) {
  //   finalTerms =
  //       '${finalTerms.replaceAll(',${Terms.oneOne.desc}', '')}(${Terms.oneOne.desc})';
  // } else if (finalTerms.contains(Terms.twoTwo.desc)) {
  //   finalTerms =
  //       '${finalTerms.replaceAll(',${Terms.twoTwo.desc}', '')}(${Terms.twoTwo.desc})';
  // } else if (finalTerms.contains(Terms.threeThree.desc)) {
  //   finalTerms =
  //       '${finalTerms.replaceAll(',${Terms.threeThree.desc}', '')}(${Terms.threeThree.desc})';
  // }
  if (finalTerms == (Terms.threeThree.desc)) {
    finalTerms = '${Terms.dot.desc}(${Terms.threeThree.desc})';
  }

  // if (finalTerms.contains(Terms.block.desc)) {
  //   if (judgeInvasion(board, nextStep)) {
  //     return Terms.invasion.desc;
  //   }
  // }

  // if (finalTerms.contains(Terms.stretch.desc)) {
  //   return Terms.stretch.desc;
  // }
  printInfo('finalTerms:$finalTerms');
  if (finalTerms.contains(',')) {
    var split = finalTerms.split(',');
    split.removeWhere((element) => element.isEmpty);
    finalTerms = split[0];
  }

  if (finalTerms.isEmpty) {
    return Terms.chess.desc;
  }

  return finalTerms;
}

/// 通过坐标系来判定
String descFromCoordinates(Board board, ChessStep chessStep) {
  String commonTerms = Terms.none.desc;
  String parataxisTerms = '';
  if (chessStep.x == 0 || chessStep.y == 0) {
    return Terms.none.desc;
  }

  final nonZeroSteps = getNonZeroChessSteps(board);

  var descCoordinates = calculateDirection(chessStep.toGtp());

  int oppositeCount = 0; // 对方棋子数
  int selfCount = 0; // 己方棋子数
  List<ChessStep> selfStepList = [];
  List<ChessStep> oppositeStepList = [];

  calculate(s) {
    oppositeCount = 0;
    selfCount = 0;
    selfStepList.clear();
    oppositeStepList.clear();

    for (final step in nonZeroSteps) {
      final distance = distanceSquared(chessStep, step.x, step.y);
      // printInfo('distance:$distance');
      if (distance == s) {
        if (step.bw != chessStep.bw) {
          oppositeCount++;
          oppositeStepList.add(step);
        } else {
          selfCount++;
          selfStepList.add(step);
        }
      }
    }
  }

  for (int s = 1; s < 3; s++) {
    calculate(s);

    /// 常用术语
    commonTerms = judgeCommonTerms(
      s,
      oppositeCount,
      selfCount,
      selfStepList: selfStepList,
      oppositeStepList: oppositeStepList,
      board: board,
      chessStep: chessStep,
      descCoordinates: descCoordinates,
    );
    printInfo('常用术语:$commonTerms');
    if (commonTerms.isNotEmpty) {
      break;
    }
  }

  // printInfo('commonTerms:$commonTerms');

  if (highPriorityCommonTermsList.contains(commonTerms)) {
    return commonTerms;
  }

  Terms compositeTerms = Terms.none;

  if (!isHaveJudgeComposite) {
    /// 复合术语
    compositeTerms = judgeCompositeTerms(
      board,
      chessStep,
      descCoordinates: descCoordinates,
    );
  }

  /// 复合术语中含有优先级高的术语时,直接返回
  var index = hasCommonElement(
    highPriorityCommonTermsList,
    compositeTerms.desc,
  );
  if (index >= 0) {
    return highPriorityCommonTermsList[index];
  }

  parataxisTerms = judgeParataxisTerms(chessStep, board: board);

  printInfo('并列术语:$parataxisTerms');

  /// 特殊术语
  String specialTerms = judgeSpecialTerms(board, chessStep);
  printInfo('特殊术语:$specialTerms');

  /// 总结判定
  String combineTerms = judgeCombineTerms(board, chessStep);
  printInfo('组合术语:$combineTerms');

  printInfo(
    '${commonTerms.isNotEmpty ? '常用术语:$commonTerms' : ''}${compositeTerms.desc.isNotEmpty ? ',复合术语:${compositeTerms.desc}' : ''}'
    '${parataxisTerms.isNotEmpty ? ',并列术语:$parataxisTerms' : ''}${specialTerms.isNotEmpty ? ',特殊术语:$specialTerms' : ''}${combineTerms.isNotEmpty ? ',组合术语:$combineTerms' : ''}',
  );
  String finalTerms =
      '$commonTerms,${compositeTerms.desc},$parataxisTerms,$specialTerms,$combineTerms';
  return finalTerms;
}

// if (type == 0) {
//   if (board.currNode.c.isEmpty) {
//     board.currNode.c = chessDescription(board, type: type);
//   }
//   return board.currNode.c;
// } else {
//   return chessDescription(board, type: type);
// }
